<template>
	<view class="content">
		<view class="one" @click="openBlue">初始化蓝牙</view>
		<view class="one" @click="searchBlue">开始搜索蓝牙</view>
		<view class="one" @click="createBlue">连接蓝牙</view>
		<view class="one" @click="getBLEDeviceServices">获取设备特征</view>
		<view class="one" @click="writeBLECharacteristicValue">写入</view>
		<view class="one" @click="readBLECharacteristicValue">读取</view>
		<view class="one">
			<input type="text" placeholder="输入" v-model="txt">
		</view>
	</view>
</template>
<script>
	import encoding from '../../static/encoding.js'
	export default {
		data() {
			return {
				device: [], //搜索到的设备
				deviceId: '', //设备id
				serverList: [], //服务
				serviceId: '',
				characteristics: [], //特征值
				characteristicId: '', //特征值uuid
				writeId: '', //可写
				readId: '', //可读·
				txt: ''
			}
		},
		mounted() {

		},
		methods: {
			openBlue() { //初始化蓝牙
				uni.openBluetoothAdapter({
					success(res) {
						//console.log('初始化蓝牙成功',res)
						uni.getBluetoothAdapterState({ //检测蓝牙是否打开 //获取本机蓝牙适配器状态
							//蓝牙的匹配状态
							success: (res1) => {
								console.log(res1, "“本机设备的蓝牙已打开”");
							},
							fail(error) {
								uni.showToast({
									icon: "none",
									title: "查看手机蓝牙(安卓蓝牙定位)是否打开"
								});
							},
						});
					},
					fail(err) {
						console.log('初始化蓝牙失败')
						uni.showToast({
							title: "请打开蓝牙",
							icon: "error"
						})
						console.error(err)
					}
				})
			},
			searchBlue() { //搜索监听蓝牙
				var that = this
				uni.startBluetoothDevicesDiscovery({
					allowDuplicatesKey: false, //允许重复上报同一个设备
					success: (res) => {
						console.log('搜索蓝牙成功 success', res);
						//监听寻找到新设备的事件
						that.onBluetoothDeviceFound();
					},
					fail(err) {
						console.log('搜索失败')
						console.error(err)
					}
				})
			},
			onBluetoothDeviceFound() { // 获取设备列表
				uni.onBluetoothDeviceFound((res) => {
					//console.log(res.devices, '搜索完成所有的设备列表')

					var that = this
					that.device = res.devices //搜索到的设备
					
					//console.log(JSON.stringify(that.device))
					//that.deviceId = res.devices[0].deviceId
					res.devices.forEach((item) => { //搜索指定设备
						if (item.name == "GL-BLE#00") { //REGLOCK_4ed8
							that.deviceId = item.deviceId
							console.log('deviceId:', item.deviceId)
						}
					})
				})

				//获取到指定设备之后  停止搜索
				// uni.stopBluetoothDevicesDiscovery({
				// 	success(res) {
				// 		console.log('停止搜索蓝牙', res)
				// 	}
				// })

			},
			createBlue() { //连接蓝牙
				let that = this;
				console.log(that.deviceId, '========')

				uni.createBLEConnection({
					deviceId: that.deviceId,
					success(res) {
						console.log(res, '连接成功')

						//连接成功之后  停止搜索
						uni.stopBluetoothDevicesDiscovery({
							success(res) {
								console.log('停止搜索蓝牙', res)
							}
						})

						uni.getConnectedBluetoothDevices({ //已连接
							success(res) {
								console.log(res.devices, '已连接过的设备')
							}
						})
					},
					fail(res) {
						uni.showToast({
							title: "蓝牙连接失败",
							icon: "none",
						});
						//uni.hideLoading()
					},
					computed(res) {
						//设备获取完成之后  停止搜索
						uni.stopBluetoothDevicesDiscovery({
							success(res) {
								console.log('停止搜索蓝牙', res)
							}
						})
					}
				});

			},
			//获取蓝牙设备所有服务(service)。
			getBLEDeviceServices() {
				const _this = this;
				console.log(_this.deviceId);
				setTimeout(() => {
					uni.getBLEDeviceServices({
						// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
						deviceId: _this.deviceId,
						success: res => { //此时需要循环遍历每个serviceId获取到特征值，但是在厂商中只有6e4开头获取到的特征值才能操作蓝牙
							console.log('获取蓝牙设备所有服务serviceId:', JSON.stringify(res.services));
							_this.serverList = res.services;

							console.log(JSON.stringify(res.services[2].uuid));

							_this.serviceId = res.services[2].uuid; //选择支持的uuid
							_this.getBLEDeviceCharacteristics(); //获取设备特征
						},
						fail: res => {
							console.log(res);
						}
					});
				}, 1000);
			},
			getBLEDeviceCharacteristics() { //获取设备特征
				var that = this
				console.log("进入特征");
				setTimeout(() => {
					uni.getBLEDeviceCharacteristics({
						// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
						deviceId: that.deviceId,
						// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
						serviceId: that.serviceId,
						success: (res) => {
							console.log(res, '特征getBLEDeviceCharacteristics')
							//	that.characteristics = res.characteristics

							//	that.characteristicId = res.characteristics[0].uuid
							for (var i = 0; i < res.characteristics.length; i++) {
								if (res.characteristics[i].properties.notify === true) { //可通知
									that.characteristics = res.characteristics[i];
									that.characteristicId = res.characteristics[i].uuid;
								}

								if (res.characteristics[i].properties.write ===
									true) { //可写 notify也要true
									that.characteristics = res.characteristics[i];
									that.writeId = res.characteristics[i].uuid;
								}
								if (res.characteristics[i].properties.read === true) { //可读
									that.characteristics = res.characteristics[i];
									that.readId = res.characteristics[i].uuid;
								}
							}

							setTimeout(() => {
								that.notifyBLECharacteristicValueChange()
							}, 3000);
						},
						fail: (res) => {
							console.log(res)
						}
					})

				}, 1000)
			},
			// 启用 notify 功能
			notifyBLECharacteristicValueChange() {
				const _this = this;
				uni.notifyBLECharacteristicValueChange({
					state: true,
					deviceId: _this.deviceId,
					serviceId: _this.serviceId,
					characteristicId: _this.characteristicId,
					success: function(res) {
						console.log("启用notify成功", res);

						setTimeout(() => { //接收消息的方法
							_this.onBLECharacteristicValueChange();
						}, 2000);
					},
					fail: function(res) {
						console.log("启用notify失败", res);
					},
				});
			},
			//监听设备返回数据的接收
			onBLECharacteristicValueChange() {
				var that = this;
				uni.onBLECharacteristicValueChange((res) => {
					console.log(res, '返回数据')

					// 结果里有个value值，该值为 ArrayBuffer 类型
					let resHex = that.ab2hex(res.value)
					console.log(resHex, '16进制') //ArrayBuffer转16进制后的结果
					// 最后将16进制转换为ascii码，就能看到对应的结果 字母 数字
					let result = that.hexToStr(resHex)
					console.log(result, '16进制转成ASCII码') //16进制 转成 ASCII码 汉字

				});
			},
			ab2hex(buffer) { //接收转换
				// ArrayBuffer转16进度字符串示例
				const hexArr = Array.prototype.map.call(new Uint8Array(buffer), function(bit) {
					return ('00' + bit.toString(16)).slice(-2);
				});
				return hexArr.join('');
				console.log(hexArr)
			},
			hexToStr(hex) { //转成字符串汉字
				// 去掉字符串首尾空格
				let trimedStr = hex.trim()
				// 判断trimedStr前两个字符是否为0x，如果是则截取从第三个字符及后面所有，否则返回全部字符
				let rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ? trimedStr.substr(2) : trimedStr
				// 得到rawStr的长度
				let len = rawStr.length
				// 如果长度不能被2整除，那么传入的十六进制值有误，返回空字符
				if (len % 2 !== 0) {
					return ""
				}
				let curCharCode // 接收每次循环得到的字符
				let resultStr = [] // 存转换后的十进制值数组
				for (let i = 0; i < len; i = i + 2) {
					curCharCode = parseInt(rawStr.substr(i, 2), 16)
					resultStr.push(curCharCode)
				}
				// encoding为空时默认为utf-8
				let bytesView = new Uint8Array(resultStr) // 8 位无符号整数值的类型化数组
				// TextEncoder和TextDecoder对字符串和字节流互转  
				// let str = new TextDecoder(encoding).decode(bytesView)因为小程序中没有TextDecoder,经查阅资料，下载https://github.com/inexorabletash/text-encoding并const encoding = require("./text-encoding-master/lib/encoding.js")引入后使用下面方式即可：
				let str = new encoding.TextDecoder("gbk").decode(bytesView)
				return str
			},
			readBLECharacteristicValue() { //读取二进制数据值
				let _this = this;
				uni.readBLECharacteristicValue({
					// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
					deviceId: _this.deviceId,
					// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
					serviceId: _this.serviceId,
					// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
					characteristicId: _this.readId,
					success(res) {
						console.log('readBLECharacteristicValue:', res)
					}
				})
			},
			//字符串转ArrayBuff
			strToArrayBuffer(str) {
				// 首先将字符串转为16进制
				let val = str
				for (let i = 0; i < str.length; i++) {
					if (val === '') {
						val = str.charCodeAt(i).toString(16)
					} else {
						val += ',' + str.charCodeAt(i).toString(16)
					}
				}
				console.log(val)
				// 将16进制转化为ArrayBuffer
				return new Uint8Array(val.match(/[\da-f]{2}/gi).map(function(h) {
					return parseInt(h, 16)
				})).buffer
			},
			//字符串转16进制码
			str_to_hex(str) {
				var hexCharCode = [];
				for (var i = 0; i < str.length; i++) {
					hexCharCode.push((str.charCodeAt(i)).toString(16));
				}
				hexCharCode = hexCharCode.join("");
				return hexCharCode;
			},
			writeBLECharacteristicValue() { //写入值
				let _this = this;
				//蓝牙设备写入数据时，需要将数据先转换为 ArrayBuffer
				let msg = 'hello'
				const buffer = new ArrayBuffer(msg.length)
				const dataView = new DataView(buffer)
				// dataView.setUint8(0, 0)

				for (var i = 0; i < msg.length; i++) { //只支持英文 数字
					dataView.setUint8(i, msg.charAt(i).charCodeAt())
				}


				// let _this = this;
				uni.writeBLECharacteristicValue({
					deviceId: _this.deviceId,
					serviceId: _this.serviceId,
					characteristicId: _this.writeId,
					value: buffer, //自定义内容buffer
					success(res) {
						console.log('写入成功', res)
					},
					fail(err) {
						console.log('写入失败', err)
					}
				})
			},



		}
	}
</script>

<style>
	.content {
		display: flex;
		align-items: center;
		justify-content: center;
		flex-direction: column;
	}

	.one {
		width: 690upx;
		height: 80upx;
		line-height: 80upx;
		color: #ffffff;
		margin-top: 20upx;
		background-color: #00aaff;
		text-align: center;
		border-radius: 10upx;
	}
</style>